/**
 * StageUtil Class
 * Copyright (c) 2009 designmarco
 * @author Marco Di Giuseppe | http://designmarco.com
 * marco[at]designmarco[dot]com
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package com.designmarco.utils
{
	import flash.display.Stage;
	import flash.display.StageAlign;
	import flash.display.StageQuality;
	import flash.display.StageScaleMode;
	import flash.display.DisplayObject;
	import flash.events.Event;
	/**
	 * StageUtil provides a central reference to the Stage,
	 * as well as providing the ability for any class to subscribe
	 * to notifications whenever a stage resize event occurs.
	 * @example
	  <listing>
		<code>
		import com.designmarco.utils.StageUtil; <br/><br/>
		
		StageUtil.getInstance().activate(stage, this); //pass stage reference to activate <br/><br/>

		public function updateResize():void <br/>
		{<br/>
			//code to be executed when stage is resized <br/>
		}
		</code>
		</listing>
	 */
	public class StageUtil
	{
		/** DisplayObjects registered to recieve event notifications */
		protected var subscribers:Array;
		
		/** If curently listening to the Event.RESIZE */
		private var _active:Boolean;
		
		/** Reference to the Stage */
		private var _stage:Stage;
		
		/** @private */
		private static var allowInstantiation:Boolean;
		
		/** @private */
		private static var instance:StageUtil;
		/**
		 * Construct an Instance of StageUtil
		 */
		public function StageUtil()
		{
			if (!allowInstantiation)
				throw new Error("Error, Already An Instance");
			else
			{
				instance = this;
				subscribers = [];
			}
		}

		/**
		 * Initialize StageUtil and begin listening to the stage resize event
		 * @param	value	stage reference
		 */
		public function activate(stage:Stage = null, target:DisplayObject = null):void
		{
			if (stage)
			{
				_stage 					= stage;
				_stage.stageFocusRect 	= false;
				_stage.quality 			= StageQuality.HIGH;
				_stage.align 			= StageAlign.TOP_LEFT;
				_stage.scaleMode 		= StageScaleMode.NO_SCALE;
				
				initNotify(target);
			}
		}

		/**
		 * Create Event to Listen for Stage Resize Notifications
		 */
		public function initNotify(target:DisplayObject = null):void
		{
			if (!_active)
			{
				_active = true;
				_stage.addEventListener(Event.RESIZE, notifyResize);
				if (target)	addSubscriber(target);
			}
		}

		/**
		 * Resize Event Handler calls the function
		 * updateResize on all registered subscribers
		 * @param	event 	 Event.RESIZE
		 */
		public function notifyResize(event:Event = null):void
		{
			var i:int = subscribers.length;
			while(i--)
			{
				subscribers[i].updateResize();
			}
		}

		/**
		 * Removes Subscribed Item
		 * @param	target 	 subscriber being removed
		 * @return 	true     if subscriber was removed successfully
		 */
		public function removeSubscriber(target:DisplayObject):Boolean
		{
			var i:int = subscribers.length;
			while(i--)
			{
				if (subscribers[i] == target)
				{
					subscribers.splice(i, 1);
					return true;
				}
			}
			return false;
		}

		/**
		 * Registers a New Subscriber
		 * @param	target	DisplayObject to receive notifications
		 * @return	true 	if adding subscriber was successful
		 */
		public function addSubscriber(target:DisplayObject):Boolean
		{
			if (subscribers == null) subscribers = [];
		
			var i:int = subscribers.length;
			while(i--)
			{
				if (subscribers[i] == target) return false;
			}
			
			subscribers[subscribers.length] = target;
			return true;
		}

		/**
		 * Clean-Up Method
		 */
		public function destroy():void
		{
			_stage.removeEventListener(Event.RESIZE, notifyResize);
			
			subscribers = [];
			_active 	= false;
			_stage 		= null;
			instance 	= null;
		}

		/**
		 * Set Reference to Stage
		 * @param value		stage reference
		 */
		public function set stage(value:Stage):void
		{
			_stage = value;
		}

		/**
		 * @return stage reference
		 */
		public function get stage():Stage
		{
			if (_stage)
				return _stage;
			else
				return null;
		}

		/**
		 * @return true if listening to the stage resize event
		 */
		public function get active():Boolean
		{
			return _active;
		}

		/**
		 * StageUtil Entry Point
		 * @return StageUtil Instance
		 */
		public static function getInstance():StageUtil
		{
			if (instance == null)
			{
				allowInstantiation = true;
				instance = new StageUtil();
				allowInstantiation = false;
			}
			return instance;
		}
	}
}